package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.AppSettings;
import com.jme3.util.SkyFactory;
import java.util.ArrayList;
import java.util.List;

 
/**
 * test
 * @author normenhansen
 */
public class ModelTest extends SimpleApplication implements ActionListener{

  public static void main(String[] args) {
    AppSettings settings = new AppSettings(true); 
    settings.setResolution(1280,720);
    settings.setSettingsDialogImage("/Textures/tcc.png");
    settings.setFrameRate(60);
    ModelTest app = new ModelTest();
    app.setSettings(settings);
    app.start();
  }

  //creating nodes
  Node nav;
  Node playerShip;
  Node randomNodes = new Node();
  BulletAppState bulletAppState;
  Inputs inputs ;
  protected Spatial ship;
  
  //mark geometry
  Geometry mark;
  //misc
  int rotationFlag = 0;
  Boolean isRunning=true;
  int navFlag=0;
  
  //adding texts
  BitmapText helloText;
  BitmapText speedText;
  
  //create bullets
  int bulletIndex = -1;
  List<Bullet> bulletObjList = new ArrayList<Bullet>();
  
  public void simpleInitApp() { 
        //rootNode.attachChild(SkyFactory.createSky(
          //  assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
        rootNode.attachChild(SkyFactory.createSky(assetManager, 
                assetManager.loadTexture("Textures/skyboxes/puruple_right1.png"), 
                assetManager.loadTexture("Textures/skyboxes/puruple_left2.png"), 
                assetManager.loadTexture("Textures/skyboxes/puruple_back6.png"),
                assetManager.loadTexture("Textures/skyboxes/puruple_front5.png"),
                assetManager.loadTexture("Textures/skyboxes/puruple_top3.png"),
                assetManager.loadTexture("Textures/skyboxes/puruple_bottom4.png")));
      
        // Display a line of text with a default font
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        helloText = new BitmapText(guiFont, false);
        helloText.setSize(guiFont.getCharSet().getRenderedSize());
        helloText.setText("Ship speed Radar");
        helloText.setLocalTranslation(300, helloText.getLineHeight()+10, 0);
        guiNode.attachChild(helloText);
        
        speedText = new BitmapText(guiFont, false);
        speedText.setSize(guiFont.getCharSet().getRenderedSize());
        speedText.setLocalTranslation(700, speedText.getLineHeight()+10, 100);
        guiNode.attachChild(speedText);

        // Load a model from test_data (OgreXML + material + texture)
        ship = assetManager.loadModel("Models/ship1/ship1.mesh.j3o");
        Material ship_mat = (Material) assetManager.loadMaterial("Materials/ship1_mat.j3m");
        ship.setMaterial(ship_mat);
        ship.scale(0.005f, 0.005f, 0.005f);
        ship.rotate(0f, 0.0f, 0.0f);
        ship.setLocalTranslation(0.0f, 0.0f, 0.0f);
        
        rootNode.attachChild(ship);
        
        Sphere sphere = new Sphere(30, 30 , 50f);
        Geometry planet = new Geometry("world", sphere);
        Material planet_map = (Material) assetManager.loadMaterial("Materials/planet.j3m");
        planet.setMaterial(planet_map);
        planet.setLocalTranslation(1000f, 200f, -300.0f);
        rootNode.attachChild(planet);  
        
        Sphere sphere1 = new Sphere(30, 30 , 500f);
        Geometry planet1 = new Geometry("world", sphere1);
     
        planet1.setMaterial(planet_map);
        planet1.setLocalTranslation(3000f, 1f, 200f);
        rootNode.attachChild(planet1);
  
        //** A white ambient light source. */ 
        AmbientLight ambient = new AmbientLight();
        ambient.setColor(ColorRGBA.White.mult(1f));
        rootNode.addLight(ambient); 
        
        
        // You must add a light to make the model visible
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
        rootNode.addLight(sun);
        
        /*
        DirectionalLight sun2 = new DirectionalLight();
        sun2.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).negate());
        sun2.setColor(ColorRGBA.LightGray.mult(.25f));
        rootNode.addLight(sun2);
        */

        setCam();
        
        //SHIP NAVIGATION SYSTEM**************************
        initMark();
        //initCrossHairs();
        initKeys();
        
        setNav();
        
        setPhysics();
        setPlayer();
   }
  
  public void setCam(){
        viewPort.setBackgroundColor(new ColorRGBA(0.169f, 0.251f, 0.251f, 1.0f));                
        
        flyCam.setEnabled(false);
        
        flyCam.setEnabled(false);
        // Enable a chase cam for this target (typically the player).
        ChaseCamera chaseCam = new ChaseCamera(cam, ship, inputManager);
        chaseCam.setSmoothMotion(true);
        chaseCam.setTrailingEnabled(false);
        chaseCam.setMinVerticalRotation(-(float)Math.PI/2);
        chaseCam.setMaxDistance(1000);
        cam.setFrustumFar(100000);
  }
  public void setNav(){
        nav = new Node("Navigation");
        
        rootNode.attachChild(nav);
        nav.attachChild(makeFloor());
        nav.attachChild(makeFloor().move(0, 200, 0));
        nav.attachChild(makeWall());
        nav.attachChild(makeWall().move(0,0,200));
        nav.attachChild(makeWall().rotate(0,FastMath.PI/2,0).move(0,0,0));
        nav.attachChild(makeWall().rotate(0,FastMath.PI/2,0).move(200,0,0));
  }
  
  public void setPhysics() {
      bulletAppState = new BulletAppState();
      bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
      stateManager.attach(bulletAppState);
      bulletAppState.getPhysicsSpace().setAccuracy(1f/45f);
      
      bulletAppState.getPhysicsSpace().enableDebug(assetManager);
  }

  //PlayerShipControl object to get the player's ship
  public void setPlayer() {
      playerShip =  new Node("Player");
      playerShip.addControl(new PlayerShipControl(cam, playerShip, bulletAppState, assetManager, this));
      rootNode.attachChild(playerShip);
  }
  @Override
  public void simpleUpdate(float tpf) {

    float[] newfl = new float[3];
    newfl = ship.getWorldRotation().toAngles(newfl);
    Vector3f shipRot = new Vector3f(newfl[0], newfl[1], newfl[2]);
    Quaternion nq = new Quaternion();
    
    Vector3f v = new Vector3f(ship.getWorldRotation().multLocal(Vector3f.UNIT_Z.clone()));       
        
    Vector3f newCoords = v.mult(shipSpeed*0.001f);
     ship.move(newCoords);
     nav.move(newCoords);
    if ( navFlag == 1){
 
        Vector3f dir = mark.getWorldTranslation().subtract(ship.getWorldTranslation()).normalize();
        nq= ship.getWorldRotation();
        Quaternion shipRotation = new Quaternion();
        shipRotation.lookAt(dir, Vector3f.UNIT_Y);
        shipRotation.negate();
            //rotationFlag = 0;
       
      //  System.out.println("NQ: "+nq);
       // System.out.println("ship: "+shipRot.y );
       // System.out.println("target: " +dir.z);
        ship.setLocalRotation(nq.slerp(nq, shipRotation, 0.01f));
       

     
        Vector3f markDist = (ship.getWorldTranslation().subtract(mark.getWorldTranslation()));
 
        if (markDist.length() < shipSpeed*0.01f){
            navFlag = 0;
            helloText.setText("Ship destination reached! " + markDist.length());
        }
        //ship.setLtoocalTranslation(v.x , v.y, v.z - value*speed*100);
    }
    speedText.setText("Ship speed: " + shipSpeed*0.001f);
    
    //Bullet loop
    for(int i = 0; i < bulletObjList.size();i++)
    { 
        if (bulletObjList.get(i) != null){
                
            if ((bulletObjList.get(i).DistanceTravelled())
                    < bulletObjList.get(i).DistanceToTravel()){
                
                (bulletObjList.get(i).getSpatial()).move(
                                (bulletObjList.get(i).BulletDirection()).mult(
                        bulletObjList.get(i).getSpeed()+tpf));
                
                bulletObjList.get(i).setChange();
            }
        
        
            else {
                rootNode.detachChild(bulletObjList.get(i).getSpatial());
                
            }
        }
    }
  } 

    /** Custom Keybinding: Map named actions to inputs. */
 
  float shipSpeed = 0f;

    public void onAction(String name, boolean isPressed, float tpf) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    //Initiate stuff
    protected void initMark(){
        Sphere sphere = new Sphere(30, 30, 0.2f);
        mark = new Geometry("Marker", sphere);
        
        Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mark_mat.setColor("Color", ColorRGBA.Red);
        mark.setMaterial(mark_mat);
    }
    
    protected Geometry makeFloor(){
        Box box = new Box(new Vector3f(0, -100f, 0), 100, .2f, 100);
        Geometry floor = new Geometry("Game Floor", box);
        Material mat1 = (Material) assetManager.loadMaterial( "Materials/nav_mat1.j3m");
        //Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        //mat1.setColor("Color", new ColorRGBA(0f,0f,0f,.2f));
        floor.setMaterial(mat1);
        return floor;
    }

     protected Geometry makeWall(){
        Box box = new Box(new Vector3f(0, -.2f, -100), 100, 100, .2f);
        Geometry floor = new Geometry("Game Floor", box);
        Material mat1 = (Material) assetManager.loadMaterial( "Materials/nav_mat1.j3m");   
        
       // Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        //mat1.setColor("Color", new ColorRGBA(0f,0f,0f,.2f));
        floor.setMaterial(mat1);
        return floor;
    }
     
 
 
 public void initKeys() {
        // You can map one or several inputs to one named action
        inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Forward",  new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("RotateR", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("RotateL", new KeyTrigger(KeyInput.KEY_A));

        inputManager.addMapping("Shoot", 
            new KeyTrigger(KeyInput.KEY_SPACE),
            new MouseButtonTrigger(MouseInput.BUTTON_LEFT));

        // Add the names to the action listener.
        inputManager.addListener(actionListener, new String[]{"Pause","Shoot"});
        inputManager.addListener(analogListener, new String[]{"Forward", "Backward", "RotateR", "RotateL"});
      }
        
         private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Pause") && !keyPressed) {
        isRunning = !isRunning;
      }
        if(name.equals("Shoot") && !keyPressed){
        CollisionResults results = new CollisionResults();
        
        Vector2f click2d = inputManager.getCursorPosition();
        Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
        Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
        
        Ray ray = new Ray(click3d, dir);
        
        nav.collideWith(ray, results);

        for (int i = 0; i < results.size(); i++) {

            if (results.size() > 0) {
                CollisionResult closest = results.getClosestCollision();

                mark.setLocalTranslation(closest.getContactPoint());
                
                
                navFlag = 1;
                rotationFlag = 1;
                rootNode.attachChild(mark);
                
              Material bulletMaterial =  new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
              bulletMaterial.setColor("Color", ColorRGBA.Yellow);

            bulletIndex += 1;
            
            bulletObjList.add(bulletIndex,
                    (new Bullet(bulletMaterial, ship.getLocalTranslation(), dir)));

            rootNode.attachChild
                    (bulletObjList.get(bulletIndex).getSpatial());
            } else {
                rootNode.detachChild(mark);
            }
        }
        
        
    }
    }
  };
  
  private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float value, float tpf) {
      if (isRunning) {
        if (name.equals("RotateR")) {
          navFlag = 0;
          ship.rotate(0, -value*speed*2, 0);
        }
        if (name.equals("RotateL")) {
          navFlag = 0;
          ship.rotate(0, value*speed*2, 0);
        }
        if (name.equals("Backward")) {          
          shipSpeed -= 1;
          //5ship.setLocalTranslation(v.x , v.y, v.z - value*speed*100);
        }
        if (name.equals("Forward")) {
          shipSpeed += 1;
        }
      } else {
        //System.out.println("Press P to unpause.");
      }
    }
  };
}
